home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / smail-3.1.28 / util / unsharmap.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-07-11  |  18.8 KB  |  821 lines

  1. /* @(#)util/unsharmap.c    1.9 7/11/92 11:40:32 */
  2. /*
  3.  *    Copyright (C) 1988 Ronald S. Karr and Landon Curt Noll
  4.  *    Copyright (C) 1992 Ronald S. Karr
  5.  * 
  6.  * See the file COPYING, distributed with smail, for restriction
  7.  * and warranty information.
  8.  */
  9.  
  10. /*
  11.  * unsharmap - unshar a USENET comp.news.maps article
  12.  *
  13.  * usage:  unsharmap [-d dir] < filelist > log
  14.  *
  15.  *       -d dir    - cd to 'dir' before unsharing
  16.  *       -s spooldir    - news spool directory
  17.  *       -n newsgroups - colon separated list of allowed newsgroups
  18.  *
  19.  * where "filelist" contains a list of files that are in the format below.
  20.  *
  21.  * The USENET map project distributes files in the following format:
  22.  *
  23.  * The header, which starts at the firts line and continues up until
  24.  * there is a blank line as the follow lins it:
  25.  *
  26.  *    Newsgroups: comp.mail.maps
  27.  *    Subject: UUCP ...
  28.  *    Message-ID: ...
  29.  *    Date: ...
  30.  *    Approved: ...
  31.  *
  32.  * These lines are not the complete list, nor do they show up in that order.
  33.  * After the header is a blank line.  Next comes the shar file preamble
  34.  * which consists of a bunch of lines that begin with a :, followed
  35.  * by the 2 lines:
  36.  *
  37.  *    echo shar: extracting THE-FILE-NAME
  38.  *    cat << 'SHAR_EOF' > THE-FILE-NAME
  39.  *
  40.  * what follows is the map data intended to override THE-FILE-NAME in the
  41.  * UNSHAR_MAP_DIR directory.  The final 3 lines:
  42.  *
  43.  *    SHAR_EOF
  44.  *    :   End of shell archive
  45.  *    exit 0
  46.  *
  47.  * terminate the shar file, and are not considered a part of the map data.
  48.  *
  49.  * For each shar file processed, the following information is written
  50.  * to stdout:
  51.  *
  52.  *    filename read
  53.  *    filename written
  54.  *    subject line
  55.  *    message-ID
  56.  *    date
  57.  *    approved info
  58.  *    any error message
  59.  *
  60.  * All error message lines begin with 'error:'.
  61.  *
  62.  * exits by 0 if there was no errors, non-0 otherwise.
  63.  */
  64.  
  65. #include <stdio.h>
  66.  
  67. #define HEADER_OK 1            /* the article header is correct */
  68. #define HEADER_ERROR 2            /* bad header, skip and log */
  69. #define HEADER_SKIP 3            /* not a map shar, ignore file */
  70.  
  71. char *program;                /* our name */
  72. char err[BUFSIZ+1];            /* error and log message */
  73. char buf[BUFSIZ+1];            /* input buffer */
  74. char mapname[BUFSIZ+1];            /* name of the output map file */
  75. int lineno = 0;                /* current line number */
  76. char *newsgroups = "comp.mail.maps";    /* : list of allowed newsgroups */
  77. char *newsspool = NULL;            /* news article spool directory */
  78. char *mapdir = NULL;            /* destination dir for maps */
  79.  
  80. char *get_date();            /* system dependent date string */
  81. void logit();                /* write to log and error log */
  82. int check_header();            /* check the article header */
  83. void skip_article();            /* skip a bad article */
  84. void ignore_article();            /* ignore the non-map article */
  85. char *check_preamble();            /* check shar preamble, get map name */
  86. int write_map();            /* write a map file */
  87. char *check_newline();            /* check to be sure we read a '\n' */
  88.  
  89. char *xmalloc();            /* for string.c and strcolon()*/
  90. char *xrealloc();            /* for string.c and strcolon() */
  91.  
  92. extern char *strcolon();        /* grap strcolon() from src/string.c */
  93.  
  94. main( argc, argv )
  95.     int argc;                /* arg count */
  96.     char *argv[];            /* args */
  97. {
  98.     char filename[BUFSIZ+1];        /* name of the input article */
  99.     char *pathname;            /* file pathname */
  100.     char *p;                /* pointer */
  101.     int c;                /* the option flag */
  102.     int header;                /* HEADER_OK,ERROR,SKIP */
  103.     int errors=0;            /* number of problems found */
  104.     FILE *article;            /* input article stream */
  105.     extern char *optarg;        /* the option argument */
  106.     extern int optind;            /* operand index */
  107.  
  108.     /*
  109.      * parse args
  110.      */
  111.     program = argv[0];
  112.     while ((c = getopt(argc, argv, "d:n:s:")) != EOF) {
  113.     switch(c) {
  114.     case 'd':            /* directory to cd to */
  115.         mapdir = optarg;
  116.         break;
  117.  
  118.     case 's':
  119.         newsspool = optarg;
  120.         break;
  121.  
  122.     case 'n':
  123.         newsgroups = optarg;
  124.         break;
  125.  
  126.     case '?':
  127.         sprintf(err,
  128.             "error: usage: %s [-d dir] < filelist > log 2> error\n",
  129.             program);
  130.         logit(err);
  131.         sprintf(err, "exiting: status: 1 -  %s", get_date());
  132.         logit(err);
  133.         exit(1);
  134.         break;
  135.     }
  136.     }
  137.     if (optind != argc) {
  138.     sprintf(err, "error: usage: %s [-d dir] < filelist > log 2> error\n",
  139.         program);
  140.     logit(err);
  141.     sprintf(err, "exiting: status: 1 -  %s", get_date());
  142.     logit(err);
  143.     exit(1);
  144.     }
  145.  
  146.     /*
  147.      * process all file names on input
  148.      */
  149.     sprintf(err, "starting: %s", get_date());
  150.     logit(err);
  151.     while (fgets(filename, BUFSIZ, stdin) != NULL) {
  152.  
  153.     if ((p = check_newline(filename)) == NULL) {
  154.         sprintf(err, "error: filename longer than %d chars\n", BUFSIZ-2);
  155.         logit(err);
  156.         sprintf(err, "exiting: status: 2 -  %s", get_date());
  157.         logit(err);
  158.         exit(2);
  159.     }
  160.     *p = '\0';    /* remove the newline from the filename */
  161.  
  162.     /*
  163.      * open the map file
  164.      *
  165.      * if the filename does not begin with a /, then prepend the
  166.      * newsspool directory to it
  167.      */
  168.  
  169.     lineno = 0;            /* clear the line count */
  170.     if (filename[0] == '/' || newsspool == NULL) {
  171.         pathname = xmalloc(strlen(filename) + 1);
  172.         strcpy(pathname, filename);
  173.     } else {
  174.         pathname = xmalloc(strlen(filename) + strlen(newsspool) + 2);
  175.         sprintf(pathname, "%s/%s", newsspool, filename);
  176.     }
  177.  
  178.     article = fopen(pathname, "r");
  179.     if (article == NULL) {
  180.         sprintf(err, "error: cannot open article: %s\n", pathname);
  181.         logit(err);
  182.         free(pathname);
  183.         ++errors;
  184.         continue;
  185.     }
  186.     sprintf(err, "filename: %s\n", pathname);
  187.     logit(err);
  188.     free(pathname);
  189.  
  190.     /*
  191.      * verify the article header
  192.      *
  193.      * close file if error or skip
  194.      */
  195.     switch (header = check_header(article)) {
  196.     case HEADER_OK:            /* we have a good header */
  197.         break;
  198.     case HEADER_ERROR:        /* the article is bad, skip & log */
  199.         skip_article(article, filename);
  200.         ++errors;
  201.         break;
  202.     case HEADER_SKIP:        /* not a map article, ignore it */
  203.         ignore_article(article, filename);
  204.         break;
  205.     default:            /* how did we get here? */
  206.         sprintf(err, "error: check_header returned %d, why?\n", header);
  207.         logit(err);
  208.         sprintf(err, "exiting: status: 3 -  %s", get_date());
  209.         logit(err);
  210.         exit(3);
  211.     }
  212.     if (header != HEADER_OK) {
  213.         continue;            /* try another file */
  214.     }
  215.  
  216.     /*
  217.      * check the shar preamble, get the shar file name
  218.      */
  219.     if (check_preamble(article) == NULL) {
  220.         skip_article(article, filename);
  221.         ++errors;
  222.         continue;
  223.     }
  224.  
  225.     /*
  226.      * write the map, verify final lines
  227.      */
  228.     if (write_map(article) != 0) {
  229.         skip_article(article, filename);
  230.         ++errors;
  231.         continue;
  232.     }
  233.  
  234.     /*
  235.      * all done with this article
  236.      */
  237.     fclose(article);
  238.     fflush(stdout);
  239.     }
  240.  
  241.     /*
  242.      * note if everything went ok
  243.      */
  244.     sprintf(err, "exiting: status: %d -  %s", (errors>0) ? 4 : 0, get_date());
  245.     logit(err);
  246.     exit( (errors>0) ? 4 : 0 );
  247. }
  248.  
  249.  
  250. /*
  251.  * get_date - get the date followed by newline in the standard way
  252.  *
  253.  * returns the date in ctime(3) format
  254.  */
  255. char *
  256. get_date()
  257. {
  258.     extern long time();
  259.     long clock = time((long *)0);   /* seconds since 1-jan-1970 0:00:00 GMT */
  260.     char *ctime();            /* convert clock into string */
  261.  
  262.     return(ctime(&clock));
  263. }
  264.  
  265.  
  266. /*
  267.  * log - write a message to the log
  268.  */
  269. void
  270. logit( msg )
  271.     char *msg;                /* the message to write */
  272. {
  273.     /* write to the log */
  274.     fputs(msg, stdout);
  275. }
  276.  
  277.  
  278. /*
  279.  * check_header - check the article header
  280.  *
  281.  * This routine verifies that a article header has the following lines:
  282.  *
  283.  *    Newsgroups: comp.mail.maps
  284.  *    Subject: UUCP ...
  285.  *    Message-ID: ...
  286.  *    Date: ...
  287.  *    Approved: ...
  288.  *
  289.  * The text of all but the Newsgroups lines are logged.  If the Newsgroups
  290.  * line is bad, that too is logged.  The header ends before a blank line.
  291.  * The final blank line is read and discarded.
  292.  *
  293.  * returns HEADER_OK is all 5 header lines were read and were valid,
  294.  *         HEADER_ERROR is the header was bad and needs to be skipped & logged,
  295.  *       HEADER_SKIP if the file is not a UUCP shar file and should be skipped
  296.  */
  297. int
  298. check_header( article )
  299.     FILE *article;            /* the article stream */
  300. {
  301.     int saw_groups=0;            /* 1 ==> saw Newsgroups: */
  302.     int saw_subject=0;            /* 1 ==> saw Subject: */
  303.     int saw_message=0;            /* 1 ==> saw Message-ID: */
  304.     int saw_date=0;            /* 1 ==> saw Date: */
  305.     int saw_approved=0;            /* 1 ==> saw Approved: */
  306.     char *p;                /* temp */
  307.  
  308.     /*
  309.      * read the header
  310.      */
  311.     do {
  312.     /*
  313.      * read the line
  314.      */
  315.     clearerr(article);
  316.     if (fgets(buf, BUFSIZ, article) == NULL) {
  317.         if (ferror(article)) {
  318.         sprintf(buf, "error: bad header read after line %d\n", lineno);
  319.         logit(err);
  320.         } else {
  321.         logit("error: EOF while reading the header\n");
  322.         }
  323.         return(HEADER_ERROR);
  324.     }
  325.     ++lineno;            /* count this line */
  326.     if (! check_newline(buf)) {
  327.         sprintf(err, "error: line %d, header line too long\n", lineno);
  328.         logit(err);
  329.         return(HEADER_ERROR);
  330.     }
  331.  
  332.     /*
  333.      * look for special types
  334.      */
  335.     switch (buf[0]) {
  336.     case 'n':
  337.     case 'N':            /* could be Newsgroups: */
  338.         if (strncmpic("Newsgroups: ", buf, 12) == 0) {
  339.         for (p = strcolon(newsgroups); p; p = strcolon((char *)NULL)) {
  340.             if (strncmpic(buf + 12, p, strlen(p)) == 0 &&
  341.             buf[12 + strlen(p)] == '\n')
  342.             {
  343.             break;
  344.             }
  345.         }
  346.         if (p != NULL) {
  347.             saw_groups = 1;
  348.         } else {
  349.             sprintf(err, "error: line %d, bad %s", lineno, buf);
  350.             logit(err);
  351.             return(HEADER_ERROR);
  352.         }
  353.         }
  354.         break;
  355.     case 's':
  356.     case 'S':            /* Subject: buf */
  357.         if (strncmpic("Subject: ", buf, 9) == 0) {
  358.         if (strncmpic("Subject: UUCP ", buf, 14) == 0) {
  359.             saw_subject = 1;
  360.             logit("    ");
  361.             logit(buf);
  362.         } else {
  363.             logit("    ");
  364.             logit(err);
  365.             return(HEADER_SKIP); /* not a shar map file */
  366.         }
  367.         }
  368.         break;
  369.     case 'm':
  370.     case 'M':            /* Message-ID: buf */
  371.         if (strncmpic("Message-ID: ", buf, 12) == 0) {
  372.             saw_message = 1;
  373.             logit("    ");
  374.             logit(buf);
  375.         }
  376.         break;
  377.     case 'd':
  378.     case 'D':            /* Message-ID: buf */
  379.         if (strncmpic("Date: ", buf, 6) == 0) {
  380.         saw_date = 1;
  381.         logit("    ");
  382.         logit(buf);
  383.         }
  384.         break;
  385.     case 'a':
  386.     case 'A':            /* Message-ID: buf */
  387.         if (strncmpic("Approved: ", buf, 10) == 0) {
  388.         saw_approved = 1;
  389.         logit("    ");
  390.         logit(buf);
  391.         }
  392.         break;
  393.     }
  394.  
  395.     } while(strcmp("\n", buf) != 0);    /* while heading the header */
  396.  
  397.     /*
  398.      * report if er got everything
  399.      */
  400.     if (saw_groups == 0) {
  401.     logit("error: no Newsgroups: line\n");
  402.     return(HEADER_ERROR);
  403.     }
  404.     if (saw_subject == 0) {
  405.     logit("error: no Subject: line\n");
  406.     return(HEADER_ERROR);
  407.     }
  408.     if (saw_message == 0) {
  409.     logit("error: no Message-ID: line\n");
  410.     return(HEADER_ERROR);
  411.     }
  412.     if (saw_date == 0) {
  413.     logit("error: no Date: line\n");
  414.     return(HEADER_ERROR);
  415.     }
  416.     if (saw_approved == 0) {
  417.     logit("error: no Approved: line\n");
  418.     return(HEADER_ERROR);
  419.     }
  420.     return(HEADER_OK);            /* passed all the tests */
  421. }
  422.  
  423. /*
  424.  * skip_article - skip article, log and close it
  425.  */
  426. void
  427. skip_article( article, filename )
  428.     FILE *article;            /* the article stream */
  429.     char *filename;            /* the filename we are skipping */
  430. {
  431.     /*
  432.      * log that we are skipping the remainder of the article
  433.      */
  434.     sprintf(err, "    skipping: %s after reading line %d\n", filename, lineno);
  435.     logit(err);
  436.  
  437.     /*
  438.      * close the stream
  439.      */
  440.     fclose(article);
  441.  
  442.     /*
  443.      * report the close
  444.      */
  445.     sprintf(err, "finished: %s\n", filename);
  446.     logit(err);
  447.     return;
  448. }
  449.  
  450.  
  451. /*
  452.  * ingore_article - ignore an article, close and report it
  453.  */
  454. void
  455. ignore_article( article, filename )
  456.     FILE *article;            /* the article stream */
  457.     char *filename;            /* the filename we are skipping */
  458. {
  459.     /*
  460.      * log that we are ignoring the remainder of the article
  461.      */
  462.     sprintf(err, "    ignore non map file: %s after reading line %d\n",
  463.         filename, lineno);
  464.     logit(err);
  465.  
  466.     /*
  467.      * close the stream
  468.      */
  469.     fclose(article);
  470.  
  471.     /*
  472.      * report the close
  473.      */
  474.     sprintf(err, "finished: %s\n", filename);
  475.     logit(err);
  476.     return;
  477. }
  478.  
  479.  
  480. /*
  481.  * check_preamble - check for a valid shar preamble
  482.  *
  483.  * The shar preamble consists of a bunch of lines that begin with :,
  484.  * followed by the 2 lines:
  485.  *
  486.  *    echo shar: extracting THE-FILE-NAME
  487.  *    cat << 'SHAR_EOF' > THE-FILE-NAME
  488.  *
  489.  * Any other line is printed to both logs as an error.  The "THE-FILE-NAME"
  490.  * string is returned if a valid preamble is found, NULL otherwise.
  491.  */
  492. char *
  493. check_preamble( article )
  494.     FILE *article;            /* the article stream */
  495. {
  496.     char *p;                /* pointer */
  497.     char *q;                /* pointer, NULL byte of mapname */
  498.     int bad_echo=0;            /* 1 ==> a bad echo was found */
  499.  
  500.     /*
  501.      * read the preamble
  502.      */
  503.     mapname[0] = '\0';    /* no mapname yet */
  504.     while (1) {
  505.     /*
  506.      * read the line
  507.      */
  508.     clearerr(article);
  509.     if (fgets(buf, BUFSIZ, article) == NULL) {
  510.         if (ferror(article)) {
  511.         sprintf(err, "error: bad preamble read after line %d\n",
  512.             lineno);
  513.         logit(err);
  514.         } else {
  515.         logit("error: EOF while reading the preamble\n");
  516.         }
  517.         return(NULL);
  518.     }
  519.     ++lineno;            /* count line */
  520.     if (! check_newline(buf)) {
  521.         sprintf(err, "error: line %d, preamble line too long\n", lineno);
  522.         logit(err);
  523.         return(NULL);
  524.     }
  525.  
  526.     /*
  527.      * skip the : lines and any blank lines
  528.      */
  529.     if (buf[0] == ':' || buf[0] == '\n') {
  530.         continue;
  531.     }
  532.  
  533.     /*
  534.      * look for the echo line
  535.      */
  536.     if (strncmp("echo shar: extracting ", buf, 22) == 0) {
  537.         /* grab the mapname */
  538.         for (p=buf+22, q=mapname, bad_echo=0; *p; ++p) {
  539.         /* be sure it is well formed */
  540.         switch (*p) {
  541.         case ' ':
  542.         case '\t':
  543.             bad_echo = 1;    /* unlikely char in a filename */
  544.             *q++ = *p;
  545.             break;
  546.         case '\n':        /* should be the end */
  547.             if (*(p+1) != '\0') {
  548.             bad_echo = 1;    /* why is '\n' not the end */
  549.             }
  550.             break;        /* don't copy the newline */
  551.         case '\\':        /* avoid \ and / in filenames */
  552.         case '/':
  553.             bad_echo = 1;
  554.             *q++ = *p;
  555.             break;
  556.         default:
  557.             *q++ = *p;
  558.             break;
  559.         }
  560.         }
  561.         *q = '\0';            /* NULL terminate filename */
  562.  
  563.         /* verify mapname */
  564.         if (bad_echo == 1) {
  565.         sprintf(err, "error: line %d, bad echo mapname: %s\n",
  566.             lineno, mapname);
  567.         logit(err);
  568.         return(NULL);        /* bad preamble */
  569.         }
  570.  
  571.     /*
  572.      * watch for the cat line
  573.      */
  574.     } else if (strncmp("cat << 'SHAR_EOF' > ", buf, 20) == 0) {
  575.  
  576.         /*
  577.          * compare cat filename against echo filename
  578.          */
  579.         if (mapname[0] == '\0') {
  580.         sprintf(err, "error: line %d, cat with no preceding echo: %s",
  581.             lineno, buf);
  582.         logit(err);
  583.         return(NULL);        /* bad preamble */
  584.         } else if (strncmp(buf+20, mapname, q-mapname) != 0) {
  585.         sprintf(err,
  586.             "error: line %d, echo mapname: %s != cat mapname: %s",
  587.             lineno, mapname, buf+20);
  588.         logit(err);
  589.         return(NULL);        /* bad preamble */
  590.         } else {
  591.         return(mapname);    /* found end of preamble */
  592.         }
  593.         
  594.     /*
  595.      * watch for unkown lines
  596.      */
  597.     } else {
  598.         sprintf(err, "error: line %d, unknown preamble: %s", lineno, buf);
  599.         logit(err);
  600.         return(NULL);
  601.     }
  602.     }
  603.     /* NOT REACHED */
  604. }
  605.  
  606.  
  607. /*
  608.  * write_map - write a map file
  609.  *
  610.  * Given an verified article header and shar preamble, copy the contents
  611.  * of the shar HERE_IS document up until the ending shar lines:
  612.  *
  613.  *    SHAR_EOF
  614.  *    :   End of shell archive
  615.  *    exit 0
  616.  *
  617.  * A previous call to check_preamble placed the name of the mapfile in
  618.  * the mapname array.
  619.  *
  620.  * returns 1 if all was ok, 0 otherwise.
  621.  */
  622. int
  623. write_map( article )
  624.     FILE *article;            /* the article stream */
  625. {
  626.     int fd;                /* map file descriptor */
  627.     FILE *map;                /* the map file stream */
  628.     char *mappath;
  629.  
  630.     /*
  631.      * open and truncate the map file
  632.      */
  633.     if (mapdir) {
  634.     mappath = xmalloc(strlen(mapdir) + strlen(mapname) + 2);
  635.     sprintf(mappath, "%s/%s", mapdir, mapname);
  636.     fd = creat(mappath, 0644);
  637.     free(mappath);
  638.     } else {
  639.     fd = creat(mapname, 0644);
  640.     }
  641.     if (fd < 0) {
  642.     sprintf(err, "error: unable to creat/truncate %s\n", mapname);
  643.     logit(err);
  644.     return(1);
  645.     }
  646.     map = fdopen(fd, "w");
  647.     sprintf(err, "extracting: %s\n", mapname);
  648.     logit(err);
  649.  
  650.     /*
  651.      * copy article shar data to the map file
  652.      */
  653.     while (1) {
  654.     /*
  655.      * read the line
  656.      */
  657.     clearerr(article);
  658.     if (fgets(buf, BUFSIZ, article) == NULL) {
  659.         if (ferror(article)) {
  660.         sprintf(err, "error: bad map data read after line %d\n",
  661.             lineno);
  662.         logit(err);
  663.         } else {
  664.         logit("error: EOF while reading the map data\n");
  665.         }
  666.         goto fail;
  667.     }
  668.     ++lineno;
  669.     if (! check_newline(buf)) {
  670.         sprintf(err, "error: line %d, map data line too long\n", lineno);
  671.         logit(err);
  672.         goto fail;
  673.     }
  674.  
  675.     /*
  676.      * watch for the end of the shar
  677.      */
  678.     if (strcmp("SHAR_EOF\n", buf) == 0) {
  679.         /* end of the shar file */
  680.         fclose(map);
  681.         mapname[0] = '\0';
  682.         break;            /* look for final two lines */
  683.     }
  684.  
  685.     /*
  686.      * write the line
  687.      */
  688.     if (fputs(buf, map) == EOF) {
  689.         logit("error: bad write\n");
  690.         goto fail;
  691.     }
  692.     }
  693.  
  694.     /*
  695.      * verify the : line after the end of the map
  696.      */
  697.     clearerr(article);
  698.     if (fgets(buf, BUFSIZ, article) == NULL) {
  699.     if (ferror(article)) {
  700.         sprintf(err, "error: bad ending : read after line %d\n",
  701.             lineno);
  702.         logit(err);
  703.     } else {
  704.         logit("error: EOF while reading the ending : line\n");
  705.     }
  706.     return(1);
  707.     }
  708.     ++lineno;
  709.     if (! check_newline(buf)) {
  710.     sprintf(err, "error: line %d, ending : line too long\n", lineno);
  711.     logit(err);
  712.     return(1);
  713.     }
  714.     if (buf[0] != ':') {
  715.     sprintf(err, "error: line %d, not an ending : line: %s", lineno, buf);
  716.     logit(err);
  717.     return(1);
  718.     }
  719.  
  720.     /*
  721.      * verify the exit 0
  722.      */
  723.     clearerr(article);
  724.     if (fgets(buf, BUFSIZ, article) == NULL) {
  725.     if (ferror(article)) {
  726.         sprintf(err, "error: bad ending exit read after line %d\n",
  727.             lineno);
  728.         logit(err);
  729.     } else {
  730.         logit("error: EOF while reading the ending exit line\n");
  731.     }
  732.     return(1);
  733.     }
  734.     ++lineno;
  735.     if (! check_newline(buf)) {
  736.     sprintf(err, "error: line %d, ending exit line too long\n", lineno);
  737.     logit(err);
  738.     return(1);
  739.     }
  740.     if (strcmp("exit 0\n", buf) != 0) {
  741.     sprintf(err, "error: line %d, not an ending exit line: %s",
  742.         lineno, buf);
  743.     logit(err);
  744.     return(1);
  745.     }
  746.  
  747.     /*
  748.      * if we are here, all must be ok
  749.      */
  750.     return(0);
  751.  
  752.  fail:
  753.  
  754.     /*
  755.      * if a failure was encountered, then close and remove the
  756.      * file
  757.      */
  758.  
  759.     fclose(map);
  760.     (void) unlink(mappath);
  761.  
  762.     return(1);
  763. }
  764.  
  765.  
  766. /*
  767.  * check_newline - check to be sure that the string endds in a newline
  768.  *
  769.  * returns a pointer to the newline, or NULL if none found
  770.  */
  771. char *
  772. check_newline( str )
  773.     char *str;                /* check for newline in str */
  774. {
  775.     char *p;                /* pointer */
  776.  
  777.     /* guess the newline location */
  778.     p = str + strlen(str);
  779.     p -= ((p > str) ? 1 : 0);
  780.  
  781.     /* return result of guess */
  782.     return( (*p == '\n') ? p : NULL );
  783. }
  784.  
  785. char *
  786. xmalloc(size)
  787.     unsigned size;
  788. {
  789.     extern char *malloc();
  790.     char *ret = malloc(size);
  791.  
  792.     if (ret == NULL) {
  793.     sprintf(err, "error: out of memory in xmalloc\n");
  794.     logit(err);
  795.     sprintf(err, "exiting: status: 1 -  %s", get_date());
  796.     logit(err);
  797.     exit(1);
  798.     }
  799.  
  800.     return ret;
  801. }
  802.  
  803. char *
  804. xrealloc(region, size)
  805.     char *region;
  806.     unsigned size;
  807. {
  808.     extern char *realloc();
  809.     register char *ret = realloc(region, size);
  810.  
  811.     if (ret == NULL) {
  812.     sprintf(err, "error: out of memory in xrealloc\n");
  813.     logit(err);
  814.     sprintf(err, "exiting: status: 1 - %s", get_date());
  815.     logit(err);
  816.     exit(1);
  817.     }
  818.  
  819.     return ret;
  820. }
  821.